package com.csw.android.androidtest.net.socket.tcp;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 模拟TCP消息head和body,由于tcpSocket是从连接中读取数据，整个连接过程中可能有多条消息，所以需要自己制定协议
 * 去分开消息数据
 */
public class TCPMessage {
    private static final String HEAD_SPACE = "\r\n";
    private static final String HEADER_KEY_VALUE_SPACE = ":";
    private static final byte[] HEADER_END_FLAG = "\r\n\r\n".getBytes();

    private static final String HEAD_KEY_CONTENT_LENGTH = "content_length";


    public static TCPMessage readFromStream(InputStream inputStream) throws Exception {
        //逐个字节读取，读取消息头，判断消息头内容
        StringBuilder head = new StringBuilder();
        int r;
        int matchIndex = 0;
        byte b;
        while ((r = inputStream.read()) != -1) {
            b = (byte) r;
            head.append(b);
            if (b == HEADER_END_FLAG[matchIndex]) {
                if (matchIndex == HEADER_END_FLAG.length - 1) {
                    break;
                } else {
                    matchIndex++;
                }
            } else {
                matchIndex = 0;
            }
        }
        String headStr = head.toString();
        String[] heads = headStr.split(HEAD_SPACE);
        HashMap<String, String> headMap = new HashMap<>();
        String[] kv;
        for (String h : heads) {
            kv = h.split(HEADER_KEY_VALUE_SPACE);
            if (kv.length == 2) {
                headMap.put(kv[0], kv[1]);
            }
        }
        String contentLength = headMap.get(HEAD_KEY_CONTENT_LENGTH);
        int bodySize = 0;
        if (contentLength != null) {
            try {
                bodySize = Integer.parseInt(contentLength);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        byte[] body = null;
        if (bodySize > 0) {
            body = new byte[bodySize];
            //读取body长度的数据
            int start = 0;
            int length;
            //循环读取，填满body
            while (start < body.length
                    && (length = inputStream.read(body, start, body.length - start)) != -1) {
                start += length;
            }
        }
        TCPMessage tcpMessage = new TCPMessage();
        for (Map.Entry<String, String> entry : headMap.entrySet()) {
            tcpMessage.setHead(entry.getKey(), entry.getValue());
        }
        tcpMessage.setData(body);
        return tcpMessage;
    }

    HashMap<String, String> headMap = new HashMap<>();
    private byte[] data;

    public TCPMessage() {
    }

    public TCPMessage(byte[] data) {
        setHead(HEAD_KEY_CONTENT_LENGTH, data.length + "");
        this.data = data;
    }

    private void setHead(String key, String value) {
        headMap.put(key, value);
    }

    private void setData(byte[] data) {
        this.data = data;
    }

    public byte[] getData() {
        return data;
    }

    public void write(OutputStream outputStream) throws Exception {
        StringBuilder head = new StringBuilder();
        for (Map.Entry<String, String> entry : headMap.entrySet()) {
            if (head.length() != 0) {
                head.append(HEAD_SPACE);
            }
            head.append(entry.getKey());
            head.append(HEAD_KEY_CONTENT_LENGTH);
            head.append(entry.getValue());
        }
        head.append(new String(HEADER_END_FLAG));
        outputStream.write(head.toString().getBytes());
        outputStream.write(data);
        outputStream.flush();
    }
}
